/*
 * Copyright 2010,2011 Michael Nitsche
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.mnit.basis.swt.element.steuer.rollbar.gruppe.bild.deko;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import de.mnit.basis.daten.struktur.liste.Liste;
import de.mnit.basis.daten.struktur.liste.S_Liste;
import de.mnit.basis.fehler.Fehler;
import de.mnit.basis.fehler.system.F_Sys_Datei;
import de.mnit.basis.swt.anw.A_MN_Gruppe;
import de.mnit.basis.swt.dialog.SWT_Fehler;
import de.mnit.basis.swt.element.S_SWT_Komponente;
import de.mnit.basis.swt.element.menue.SWT_MenueLeiste;
import de.mnit.basis.swt.grafik.Bild_SWT;
import de.mnit.basis.swt.timer.A_SWT_Timer;
import de.mnit.basis.sys.event.S_Verarbeite;
import de.mnit.basis.sys.event.S_Zuhoerer;

public class SWT_Fenster extends A_SWT_Fenster<SWT_Fenster> {

	protected final S_SWT_Komponente<?,?> inhalt;
	private   boolean zentriert;
	private   Display display;
	private   boolean flexibel=true;
	private   boolean schliessbar=true;


	public SWT_Fenster(S_SWT_Komponente<?,?> komponente) {
		Fehler.objekt.wenn_Null(komponente);
		this.inhalt=komponente;
	}


	public static final SWT_Fenster neu(S_SWT_Komponente<?,?> komponente) {
		return new SWT_Fenster(komponente);
	}

	public static S_Fenster<?> neu(A_MN_Gruppe<?> instanz, boolean groesseFest, int breite, int hoehe, String titel, Object... bilder) {
		SWT_Fenster f=SWT_Fenster.neu(instanz);
		if(groesseFest)
			f.s1_FesteGroesse();
		f.sGroesse(breite,hoehe);
		f.sTitel(titel);
		if(bilder!=null && bilder.length>0)
			f.sBilder(bilder);
		return f;
	}

	// BEFEHL

	public void schliessen() {
		swt().close();
		swt().dispose();
	}

	public Thread startExtern(Runnable r) {
		Fehler.objekt.wenn_Null(r);
		Thread erg=null;
		try   {
			erg=new Thread(r);
			// BUGFIX: setDaemon: Anwendung blieb sonst hängen wenn noch ein Thread lief
			erg.setDaemon(true);
			erg.start();
		}
		catch(Throwable t)   { SWT_Fehler.zeig(t,true); }
		return erg;
	}

	public void startSync(Runnable r) {
		Fehler.objekt.wenn_Null(r);
		try {
			this.display.syncExec(r);
		}
		catch(Throwable t)   { SWT_Fehler.zeig(t,true); }
	}

	public void startAsync(Runnable r) {
		Fehler.objekt.wenn_Null(r);
		try {
			this.display.asyncExec(r);
		}
		catch(Throwable t)   { SWT_Fehler.zeig(t,true); }
	}

	public void startTimer(A_SWT_Timer timer) {
		timer.start(Display.getDefault());
	}

	public void oeffnen() {
		this.oeffnen(null, null);
	}

	public void oeffnen(Shell parent) {
		this.oeffnen(parent, null);
	}

	public void oeffnen(Shell parent, S_Zuhoerer<Object> bereit) {
		this.erzeugeSWT(Display.getDefault(), parent);
		this.swt().layout();
		if(bereit!=null)
			bereit.verarbeite(null);
	}

	// SETZE

	public SWT_Fenster s1_FesteGroesse() {
		this.PN_Erzeugt();
		this.flexibel=false;
		return this;
	}

	public SWT_Fenster s1_NichtSchliessbar() {
		this.PN_Erzeugt();
		this.schliessbar=false;
		return this;
	}

	public void sAktiv(boolean b) {
		iAktiv(this.swt().getChildren(), b);
	}

	public SWT_Fenster sGroesse(final int dx, final int dy) {
		Fehler.zahl.wenn_Ausserhalb(10,2000,dx);
		Fehler.zahl.wenn_Ausserhalb(10,2000,dy);

		wennErzeugt(new S_Verarbeite() {
			public void verarbeite() {
				Point p=swt().computeSize(dx, dy, true);
				swt().setSize(p.x,p.y);
				if(zentriert)
					zentrieren();
			}
		});
		return this;
	}

	public void sTitel(final String titel) {
		Fehler.objekt.wenn_Null(titel);
		wennErzeugt(new S_Verarbeite() {
			public void verarbeite() {
				swt().setText(titel);
			}
		});
	}

	/**
	 * Es können mehrere größen übergeben werden! Die Anwendung sucht sich dann das aus was am besten paßt!
	 */
	public SWT_Fenster sBilder(final Object... bilder) {
		Fehler.objekt.wenn_Null((Object)bilder);
		wennErzeugt(new S_Verarbeite() {
			public void verarbeite() {
				iBilder(bilder);
			}
		});
		return this;
	}

	public void sBild(final Object datei) {
		Fehler.objekt.wenn_Null(datei);
		wennErzeugt(new S_Verarbeite() {
			public void verarbeite() {
				try {
					swt().setImage(Bild_SWT.neu_Direkt(datei).gImage());
				}
				catch(F_Sys_Datei e)   { Fehler.zeig(e); }
			}
		});
	}

	public void sZentriert() {
		this.zentrieren();
	}


//	public S_SWT_Fenster sStandartKnopf(S_A_SWT_Steuer<?,Button> knopf) {
//		Fehler.objekt.wenn_Null(knopf,1);
//		this.swt().setDefaultButton(knopf.swt());
//		return this;
//	}

	// EVENT

	public SWT_Fenster eVorSchliessen(S_Zuhoerer<?> z) {
		this.zuhoererPlus("VORSCHLIESSEN",z);
		return this;
	}

	// NEU

	public SWT_MenueLeiste nMenue_Leiste() {
		SWT_MenueLeiste leiste=new SWT_MenueLeiste();
		leiste.erzeugeSWT(this.swt());
		this.swt().setMenuBar(leiste.swt());
		return leiste;
	}

	// ERZEUGEN

	// parent Shell wird für Dialoge benötigt
	public void erzeugeSWT(Display display, Shell parent) {
		this.display=display;
		this.erzeugeSWT(parent);
	}

	protected int style3() {
//		SHELL_TRIM  = CLOSE | TITLE | MIN | MAX | RESIZE;
//		DIALOG_TRIM = TITLE | CLOSE | BORDER;

		int style=SWT.SHELL_TRIM;
		if(!this.schliessbar) style=style^SWT.CLOSE;
		if(!this.flexibel) style=(style^SWT.RESIZE)^SWT.MAX;
		style= style | SWT.BORDER; //Dialog_trim wäre ohne Border, so siehts aber besser aus
		return style;
	}

	protected Shell roh(Composite vater, int style) { //TODO Optimieren wegen Performance
		if(vater!=null) {
//			this.s1_Style(SWT.APPLICATION_MODAL|SWT.PRIMARY_MODAL|SWT.SYSTEM_MODAL);
//			this.s1_Style(SWT.DIALOG_TRIM|SWT.APPLICATION_MODAL);
//			this.s1_Style(SWT.APPLICATION_MODAL);
			style=style|SWT.APPLICATION_MODAL;
		}
		if(this.display==null) this.display= vater==null ? new Display() : vater.getDisplay();
		if(vater==null) return new Shell(this.display,style);
		else            return new Shell((Shell)vater,style);
	}

	protected void init3() {
		swt().addShellListener(new ShellListener(){
			public void shellActivated(ShellEvent e)     {}
			public void shellClosed(ShellEvent e)        { zuhoererStart("VORSCHLIESSEN",null); }
			public void shellDeactivated(ShellEvent e)   {}
			public void shellDeiconified(ShellEvent e)   {}
			public void shellIconified(ShellEvent e)     {}
		});

//		Fehler.objekt.wenn_Null(manager());

//		if(position!=null)
//			if(position==POSITION.MITTE) this.zentrieren();
//			else Fehler.sonstige.da_Untypisch("POSITION derzeit nicht unterstützt: "+position);

	    swt().setLayout(new FillLayout());
	    this.inhalt.erzeugeSWT(swt());
	    swt().open();
	}

	// INTERN

	/**
	 * Zentriert das Fenster auf dem Bildschirm.
	 * Dialoge werden automatisch zentriert, wenn man die Shell übergibt!
	 */
	protected void zentrieren() {
		this.zentriert=true;
		Rectangle monitor = this.display.getPrimaryMonitor().getBounds(); //TODO Fehler!!! Evtl. noch kein Display vorhanden!
//		Rectangle display = this.display.getBounds();
		Rectangle fenster = this.swt().getBounds();

		int x = monitor.x + (monitor.width /2 - fenster.width /2);
		int y = monitor.y + (monitor.height/2 - fenster.height/2);
		swt().setLocation(x, y);
	}

	private void iBilder(Object[] bilder) {
		Fehler.objekt.wenn_Null((Object)bilder);
		try {
			S_Liste<Image> il=Liste.neu();
			for(Object i : bilder)
				il.plus(Bild_SWT.neu_Direkt(i).gImage());
			swt().setImages(il.zuArray(Image.class));
		}
		catch(F_Sys_Datei e) {
			Fehler.zeig(e);
		}
	}

	private void iAktiv(Control[] ca, boolean b) {
		for(Control c : ca) {
			if(c instanceof Composite)
				iAktiv(((Composite)c).getChildren(), b);
			c.setEnabled(b);
		}
	}

}
